package com.terrynoya.qtree
{
	import com.terrynoya.collision.ICollision;
	import com.terrynoya.common.util.MHashMap;
	import com.terrynoya.node.INode;
	import com.terrynoya.node.Node;
	
	import flash.display.DisplayObject;
	import flash.display.Graphics;
	import flash.display.Sprite;
	import flash.filters.GradientBevelFilter;
	import flash.geom.Point;
	
	/**
	 * 
	 * @author TerryYao
	 */
	public class QTreeNode
	{
		private var _q:Point;
		
		private var _w:Point;
		
		private var _s:Point;
		
		private var _a:Point;
		
		private var _childMap:MHashMap;
		
		private var _level:int;
		
		private var _parent:QTreeNode;
		
		private var _hasChilren:Boolean = false; 
		
		private var _datas:Array;
		
		/**
		 * qwsa代表NW,NE,SE,SW四个象限,和键盘的四个区域位置一样:)
		 * 这样命名比nw更快反应当前是哪个象限
		 * @param q
		 * @param w
		 * @param s
		 * @param a
		 * @param parent
		 */
		public function QTreeNode(q:Point,w:Point,s:Point,a:Point,parent:QTreeNode = null)
		{
			super();
			this._q = q;
			this._w = w;
			this._s = s;
			this._a = a;
			this._datas = new Array();
			this._childMap = new MHashMap();
			this._parent = parent;
		}
		
		

		/**
		 * 
		 * @return 
		 */
		public function get datas():Array
		{
			return _datas;
		}

		/**
		 * 
		 * @return 
		 */
		public function get parent():QTreeNode
		{
			return _parent;
		}

		/**
		 * 
		 * @param value
		 */
		public function set parent(value:QTreeNode):void
		{
			_parent = value;
			this._level = this.parent.level + 1;
		}

		/**
		 * 
		 * @return 
		 */
		public function get level():int
		{
			return this._level;
		}
		
		/**
		 * 四分一个区域生成4个子象限
		 * @param minWidth
		 * @return 
		 */
		public function divide(minWidth:int):Boolean
		{
			if(this._hasChilren)
			{
				return false;	
			}
			
			if((w.x - q.x)/2 < minWidth)
			{
				return false;
			}
			
			var up:Point = new Point((q.x + w.x)/2,q.y);
			var down:Point = new Point((s.x + a.x)/2,a.y);
			var left:Point = new Point(q.x,(a.y + q.y)/2);
			var right:Point = new Point(w.x,(s.y + w.y)/2);
			var center:Point = new Point((w.x + q.x)/2,(a.y + q.y)/2);
			
			var nw:QTreeNode = new QTreeNode(q,up,center,left,this);
			this._childMap.put(QTreeNodeType.NW,nw);
			
			var ne:QTreeNode = new QTreeNode(up,w,right,center,this);
			this._childMap.put(QTreeNodeType.NE,ne);
			
			var se:QTreeNode = new QTreeNode(center,right,s,down,this);
			this._childMap.put(QTreeNodeType.SE,se);
			
			var sw:QTreeNode = new QTreeNode(left,center,down,a,this);
			this._childMap.put(QTreeNodeType.SW,sw);
			
			this._hasChilren = true; 
			return true;
		}
		
		/**
		 * 
		 */
		public function detect():void
		{
			trace(this.toString(),"datas.length",this._datas.length);
			var allDatas:Array = new Array();
			var childrenDatas:Array;
			if(this._hasChilren)
			{
				childrenDatas = this.childNE.datas.concat(this.childNW.datas.concat(this.childSE.datas.concat(this.childSW.datas)));
				allDatas = allDatas.concat(childrenDatas);
			}
			allDatas = allDatas.concat(this.datas);
			if(this._datas.length > 1 || (this._hasChilren && childrenDatas.length > 0 && this._datas.length > 0))
			{
				for(var i:int = 0;i<allDatas.length;i++)
				{
					QTreeNoteItem(allDatas[i]).colision = true;
				} 
			}
			if(this._hasChilren) 
			{
				this.childNE.detect();
				this.childNW.detect();
				this.childSE.detect();
				this.childSW.detect();
			}
		} 
		
		/**
		 * 
		 * @param canvas
		 */
		public function drawGrid(canvas:Sprite):void
		{
			var g:Graphics = canvas.graphics;
			g.lineStyle(1,0);
			g.moveTo(q.x,q.y);
			g.lineTo(w.x,w.y);
			g.lineTo(s.x,s.y);
			g.lineTo(a.x,a.y);
			g.lineTo(q.x,q.y);
			g.endFill();
			if(!this._hasChilren)
			{
				return;
			}
			this.childNE.drawGrid(canvas);
			this.childNW.drawGrid(canvas);
			this.childSE.drawGrid(canvas);
			this.childSW.drawGrid(canvas);
		}
		
		/**
		 * 
		 * @return 
		 */
		protected function get childNW():QTreeNode
		{
			return QTreeNode(this._childMap.getValue(QTreeNodeType.NW));
		}
		
		/**
		 * 
		 * @return 
		 */
		protected function get childNE():QTreeNode
		{
			return QTreeNode(this._childMap.getValue(QTreeNodeType.NE));
		}
		
		/**
		 * 
		 * @return 
		 */
		protected function get childSE():QTreeNode
		{
			return QTreeNode(this._childMap.getValue(QTreeNodeType.SE));
		}
		
		/**
		 * 
		 * @return 
		 */
		protected function get childSW():QTreeNode
		{
			return QTreeNode(this._childMap.getValue(QTreeNodeType.SW));
		}
		
		private function pushDownOld(nodeItem:QTreeNoteItem):void
		{
			this.divide(QTree.MIN_WIDTH);
			if(!this._hasChilren)
			{
				return;
			}
			this.childNE.locate(nodeItem);
			this.childNW.locate(nodeItem);
			this.childSE.locate(nodeItem);
			this.childSW.locate(nodeItem);
		}
		
		private function pushBack(nodeItem:QTreeNoteItem):void
		{
			var node:QTreeNode;
			node = this.parent == null ? this : this.parent;
			if(node.datas.indexOf(nodeItem)==-1)
			{
				node.datas.push(nodeItem);
			}
		}
		
		/**
		 * 
		 * @param nodeItem
		 */
		public function locate(nodeItem:QTreeNoteItem):void
		{
			this.addData(nodeItem);
			if(this.isInside(nodeItem))
			{
				var len:int = this.datas.length;
				while(len > 0)
				{
					var node:QTreeNoteItem = this.datas.pop();
					this.pushDown(node).addData(node);
					len --;
				}
			}
		}
		 
		private function pushDown(nodeItem:QTreeNoteItem):QTreeNode
		{
			this.divide(QTree.MIN_WIDTH);
			if(!this._hasChilren)
			{
				return this;
			}
			if(this.childNE.isInside(nodeItem))
			{
				return this.childNE.pushDown(nodeItem); 
			}
			else if(this.childNW.isInside(nodeItem))
			{
				return this.childNW.pushDown(nodeItem); 
			}
			else if(this.childSE.isInside(nodeItem))
			{
				return this.childSE.pushDown(nodeItem); 
			}
			else if(this.childSW.isInside(nodeItem))
			{
				return this.childSW.pushDown(nodeItem); 
			}
			else
			{
				return this;
			}
		}
		
		/**
		 * 
		 * @param value
		 */
		public function addData(value:QTreeNoteItem):void
		{
			this._datas.push(value);
		}
		
		/**
		 * 
		 * @param nodeItem
		 * @return 
		 */
		public function isInside(nodeItem:QTreeNoteItem):Boolean
		{
			var qInside:Boolean = nodeItem.q.x - this.q.x >= 0 && nodeItem.q.y - this.q.y >= 0;
			var wInside:Boolean = nodeItem.w.x - this.w.x <= 0 && nodeItem.w.y - this.w.y >= 0;
			var sInside:Boolean = nodeItem.s.x - this.s.x <= 0 && nodeItem.s.y - this.s.y <= 0;
			var aInside:Boolean = nodeItem.a.x - this.a.x >= 0 && nodeItem.a.y - this.a.y <= 0;
			return qInside && wInside && sInside && aInside;
		}
		
		/**
		 * 
		 * @return 
		 */
		public function get childMap():MHashMap
		{
			return this._childMap;
		}
		
		/**
		 * 
		 * @return 
		 */
		public function toString():String
		{
			return q.toString() + "," + w.toString()+","+s.toString()+","+a.toString();
		}
		
		
		/**
		 * 
		 * @return 
		 */
		public function get a():Point
		{
			return _a;
		}
		
		/**
		 * 
		 * @param value
		 */
		public function set a(value:Point):void
		{
			_a = value;
		}
		
		/**
		 * 
		 * @return 
		 */
		public function get s():Point
		{
			return _s;
		}
		
		/**
		 * 
		 * @param value
		 */
		public function set s(value:Point):void
		{
			_s = value;
		}
		
		/**
		 * 
		 * @return 
		 */
		public function get w():Point
		{
			return _w;
		}
		
		/**
		 * 
		 * @param value
		 */
		public function set w(value:Point):void
		{
			_w = value;
		}
		
		/**
		 * 
		 * @return 
		 */
		public function get q():Point
		{
			return _q;
		}
		
		/**
		 * 
		 * @param value
		 */
		public function set q(value:Point):void
		{
			_q = value;
		}
	}
}
